package com.maixy.studyonlineapi.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.maixy.studyonlineapi.bean.Page;
import com.maixy.studyonlineapi.entity.Activity;
import com.maixy.studyonlineapi.entity.Auth;
import com.maixy.studyonlineapi.entity.Media;
import com.maixy.studyonlineapi.entity.Team;
import com.maixy.studyonlineapi.entity.User;
import com.maixy.studyonlineapi.enums.ActivityTypeEnum;
import com.maixy.studyonlineapi.enums.ActivityViewTypeEnum;
import com.maixy.studyonlineapi.enums.MediaTypeEnum;
import com.maixy.studyonlineapi.es.dao.ActivityEsDao;
import com.maixy.studyonlineapi.es.entity.ActivityEs;
import com.maixy.studyonlineapi.exceptions.TipException;
import com.maixy.studyonlineapi.mapper.ActivityMapper;
import com.maixy.studyonlineapi.result.PageData;
import com.maixy.studyonlineapi.utils.DataTypeUtil;
import com.maixy.studyonlineapi.utils.LocalDateTimeUtils;
import com.maixy.studyonlineapi.utils.OssUtil;
import com.maixy.studyonlineapi.view.ActivityView;
import com.maixy.studyonlineapi.view.MediaView;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @Classname ActivityService
 * @Description TODO
 * @Date 2020/11/8 18:50
 * @Author by maixy
 */
@Slf4j
@Service
public class ActivityService extends BaseMPlusService<Activity, Long> {
    private final ActivityMapper activityMapper;

    @Resource
    private TeamService teamService;
    @Resource
    private UserService userService;
    @Resource
    private MediaService mediaService;
    @Resource
    private AuthService authService;
    @Resource
    private ActivityContentService activityContentService;
    @Resource
    private UserAbilityService userAbilityService;
    @Resource
    private OssUtil ossUtil;
    @Resource
    private ActivityEsDao activityEsDao;
    @Autowired()
    private RestHighLevelClient restHighLevelClient;

    protected ActivityService(ActivityMapper activityMapper) {
        super(Activity.class, activityMapper);
        this.activityMapper = activityMapper;
    }

    public PageData<ActivityView> getMyActivityList(Long teamId, Long userId, String activitySearch, Integer activityType, Page page) {
        page.setHasMore(false);
        PageData<ActivityView> pageData = new PageData<>();
        pageData.setPage(page);
        pageData.setData(Collections.emptyList());
        userId = teamService.getSuperManagerUserId(teamId, userId);
        int beginIndex = (page.getPage() - 1) * page.getSize();
        if (StringUtils.isNoneBlank(activitySearch)) {
            activitySearch = "%".concat(activitySearch).concat("%");
        }
        List<Activity> activityList = activityMapper.getMyActivityList(activitySearch, activityType, userId, beginIndex, page.getSize() + 1);
        if (CollectionUtils.isEmpty(activityList)) {
            return pageData;
        }
        if (activityList.size() > page.getSize()) {
            page.setHasMore(true);
            activityList.remove(activityList.size() - 1);
        }

        List<ActivityView> activityViewList = new ArrayList<>();
        for (Activity activity : activityList) {
            activityViewList.add(convert(activity, null, null, ActivityViewTypeEnum.TEACHER.getId()));
        }
        pageData.setData(activityViewList);

        return pageData;
    }

    /**
     * 我加入的活动列表
     *
     * @param userId 用户id
     * @return List<com.maixy.studyonlineapi.view.ActivityView>
     */
    public PageData<ActivityView> getJoinActivityList(Long teamId, Long userId, Page page) {
        page.setHasMore(false);
        PageData<ActivityView> pageData = new PageData<>();
        pageData.setPage(page);
        pageData.setData(Collections.emptyList());
        int beginIndex = (page.getPage() - 1) * page.getSize();
        List<Activity> activityList = activityMapper.getJoinActivityList(userId, beginIndex, page.getSize() + 1);
        if (CollectionUtils.isEmpty(activityList)) {
            return pageData;
        }
        if (activityList.size() > page.getSize()) {
            page.setHasMore(true);
            activityList.remove(activityList.size() - 1);
        }

        List<ActivityView> activityViewList = new ArrayList<>();
        for (Activity activity : activityList) {
            activityViewList.add(convert(activity, teamId, userId, ActivityViewTypeEnum.STUDENT.getId()));
        }
        pageData.setData(activityViewList);

        return pageData;
    }


    /**
     * 活动列表
     *
     * @return List<com.maixy.studyonlineapi.view.ActivityView>
     */
    public PageData<ActivityView> activityList(Integer activityViewType, Integer activityType, Page page) {
        page.setHasMore(false);
        PageData<ActivityView> pageData = new PageData<>();
        pageData.setPage(page);
        pageData.setData(Collections.emptyList());
        int beginIndex = (page.getPage() - 1) * page.getSize();
        List<Activity> activityList;
        if (ActivityViewTypeEnum.HOT.getId().equals(activityViewType)) {
            activityList = activityMapper.getHotActivityList(activityType, beginIndex, page.getSize() + 1);
        } else {
            activityList = activityMapper.getNewActivityList(activityType, beginIndex, page.getSize() + 1);
        }
        if (CollectionUtils.isEmpty(activityList)) {
            return pageData;
        }

        if (activityList.size() > page.getSize()) {
            page.setHasMore(true);
            activityList.remove(activityList.size() - 1);
        }
        List<ActivityView> activityViewList = new ArrayList<>();
        for (Activity activity : activityList) {
            activityViewList.add(convert(activity, null, null, activityViewType));
        }
        pageData.setData(activityViewList);

        return pageData;
    }

    /**
     * 活动详情页
     *
     * @param activityId 活动id
     * @return com.maixy.studyonlineapi.view.ActivityView
     */
    public ActivityView activityDetail(Long activityId, Long teamId, Long userId) {
        Activity activity = findById(activityId);
        if (null == activity || activity.getHasDelete()) {
            throw new TipException("班级不存在或已被删除");
        }
        return convert(activity, teamId, userId, ActivityViewTypeEnum.DETAIL.getId());
    }

    public PageData<ActivityView> discoverActivityList(String activitySearch, Integer activityType, Page page) throws IOException {
        page.setHasMore(false);
        PageData<ActivityView> pageData = new PageData<>();
        pageData.setPage(page);
        pageData.setData(Collections.emptyList());
        int beginIndex = (page.getPage() - 1) * page.getSize();
        List<Activity> activityList = new ArrayList<>();

        SearchRequest request = new SearchRequest();
        request.indices("activity");
        SearchSourceBuilder builder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (StringUtils.isNotBlank(activitySearch)) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("activityName",activitySearch));
        }
        if (activityType > 0) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("activityType",activityType));
        }

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font color='red'>");
        highlightBuilder.postTags("</font>");
        highlightBuilder.field("activityName");

        builder.query(boolQueryBuilder);
        builder.highlighter(highlightBuilder);
        builder.from(beginIndex);
        builder.size(page.getSize() + 1);
        builder.sort("createTime", SortOrder.DESC);
        request.source(builder);
        SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        for (SearchHit hit : response.getHits().getHits()) {
            Activity activity = new Activity();
            activity.setId(DataTypeUtil.getLong(hit.getSourceAsMap().get("id")));
            activity.setCreateBy(DataTypeUtil.getLong(hit.getSourceAsMap().get("createBy")));
            activity.setCreateTime(DataTypeUtil.getLong(hit.getSourceAsMap().get("createTime")));
            activity.setUpdateBy(DataTypeUtil.getLong(hit.getSourceAsMap().get("updateBy")));
            activity.setUpdateTime(DataTypeUtil.getLong(hit.getSourceAsMap().get("updateTime")));
            activity.setHasDelete(DataTypeUtil.getBoolean(hit.getSourceAsMap().get("hasDelete")));
            if (null != hit.getHighlightFields().get("activityName")) {
                activity.setActivityName(DataTypeUtil.getStr(hit.getHighlightFields().get("activityName").getFragments()[0]));
            } else {
                activity.setActivityName(DataTypeUtil.getStr(hit.getSourceAsMap().get("activityName")));
            }
            activity.setActivityType(DataTypeUtil.getInteger(hit.getSourceAsMap().get("activityType")));
            activity.setActivityLogoId(DataTypeUtil.getLong(hit.getSourceAsMap().get("activityLogoId")));
            activity.setActivityDesc(DataTypeUtil.getStr(hit.getSourceAsMap().get("activityDesc")));
            activityList.add(activity);
        }
        if (CollectionUtils.isEmpty(activityList)) {
            return pageData;
        }
        if (activityList.size() > page.getSize()) {
            page.setHasMore(true);
            activityList.remove(activityList.size() - 1);
        }

        List<ActivityView> activityViewList = new ArrayList<>();
        for (Activity activity : activityList) {
            activityViewList.add(convert(activity, null, null, ActivityViewTypeEnum.DISCOVER.getId()));
        }
        pageData.setData(activityViewList);

        return pageData;
    }


    /**
     * 创建活动
     *
     * @param activityName   活动名称
     * @param activityLogoUrl 活动图片url
     * @param activityDesc   活动描述
     * @param userId         用户id
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void createActivity(String activityName, Integer activityType, String activityLogoUrl, String activityDesc, Long userId, Long teamId) {
        userId = teamService.getSuperManagerUserId(teamId, userId);
        Activity activity = new Activity();
        activity.setActivityName(activityName);
        if (null == ActivityTypeEnum.getById(activityType)) {
            throw new TipException("未知的课程类型");
        }
        if (ossUtil.exist(activityLogoUrl)) {
            MediaView mediaView = mediaService.saveMedia(MediaTypeEnum.IMAGE.getCode(), activityLogoUrl);
            activity.setActivityType(activityType);
            activity.setActivityLogoId(DataTypeUtil.getLong(mediaView.getMediaId()));
            activity.setActivityDesc(activityDesc);
            activity.setCreateBy(userId);
            activity.setCreateTime(System.currentTimeMillis());
            create(activity);
            try {
                //将数据同步到es
                ActivityEs activityEs = new ActivityEs();
                BeanUtils.copyProperties(activity, activityEs);
                activityEsDao.save(activityEs);
            } catch (Exception e) {
                log.error("创建Activity同步到ES失败,activityId:{}", activity.getId(), e);
            }
        } else {
            throw new TipException("课程Logo不存在");
        }

    }

    /**
     * 更新课程
     *
     * @param activityId     活动id
     * @param activityName   活动名称
     * @param activityLogoUrl 活动封面图片id
     * @param activityDesc   活动描述
     * @param userId         用户id
     * @param teamId         团队id
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateActivity(Long activityId, Integer activityType, String activityName, String activityLogoUrl, String activityDesc, Long userId, Long teamId) {
        userId = teamService.getSuperManagerUserId(teamId, userId);
        Activity activity = findById(activityId);
        if (null == activity || activity.getHasDelete()) {
            throw new TipException("课程不存在或已被删除");
        }
        activity.setActivityName(activityName);
        if (null == ActivityTypeEnum.getById(activityType)) {
            throw new TipException("未知的课程类型");
        }
        activity.setActivityType(activityType);
        if (StringUtils.isNotBlank(activityLogoUrl)) {
            if (ossUtil.exist(activityLogoUrl)) {
                MediaView mediaView = mediaService.saveMedia(MediaTypeEnum.IMAGE.getCode(), activityLogoUrl);
                activity.setActivityLogoId(DataTypeUtil.getLong(mediaView.getMediaId()));
            } else {
                throw new TipException("课程Logo不存在");
            }
        }
        activity.setActivityDesc(activityDesc);
        activity.setUpdateBy(userId);
        activity.setUpdateTime(System.currentTimeMillis());
        update(activity);
        try {
            //将数据同步到es
            ActivityEs activityEs = new ActivityEs();
            BeanUtils.copyProperties(activity, activityEs);
            activityEsDao.existsById(activityId);
            activityEsDao.save(activityEs);
        } catch (Exception e) {
            log.error("更新Activity同步到ES失败,activityId:{}", activityId, e);
        }
    }

    /**
     * 删除课程
     *
     * @param teamId     团队id
     * @param userId     用户id
     * @param activityId 活动id
     */
    public void deleteActivity(Long teamId, Long userId, Long activityId) {
        if (!teamService.hasPower(teamId, userId)) {
            throw new TipException("没有权限");
        }
        Activity activity = findById(activityId);
        if (null != activity && !activity.getHasDelete()) {
            activity.setHasDelete(true);
            activity.setUpdateBy(userId);
            activity.setUpdateTime(System.currentTimeMillis());
            update(activity);
        }
    }

    /**
     * 视图转换
     *
     * @param activity 活动id
     * @return com.maixy.studyonlineapi.view.ActivityView
     */
    public ActivityView convert(Activity activity, Long teamId, Long userId, Integer activityViewType) {
        ActivityView view = new ActivityView();
        view.setActivityId(String.valueOf(activity.getId()));
        Media media = mediaService.findById(activity.getActivityLogoId());
        if (null != media && !media.getHasDelete()) {
            view.setActivityLogo(media.getMediaUrl());
        }
        view.setActivityName(activity.getActivityName());
        view.setActivityType(activity.getActivityType());
        view.setCreateBy(String.valueOf(activity.getCreateBy()));
        view.setActivityDesc(activity.getActivityDesc());
        view.setCreateTimeStr(LocalDateTimeUtils.format(activity.getCreateTime(), LocalDateTimeUtils.NORMAL_DATETIME_FORMAT_NO_SECOND));
        view.setAuthNum(authService.findAuthNumByActivityId(activity.getId()));
        ActivityViewTypeEnum activityViewTypeEnum = ActivityViewTypeEnum.getById(activityViewType);
        switch (activityViewTypeEnum) {
            case TEACHER: {
                view.setActivityContentNum(activityContentService.countActivityContentNumByActivityId(activity.getId()));
                break;
            }
            case STUDENT: {
                view.setActivityContentNum(activityContentService.countActivityContentNumByActivityId(activity.getId()));
                Auth auth = authService.findAuthByUserIdAndActivityId(userId, activity.getId());
                if (null != auth && !auth.getHasDelete()) {
                    view.setJoinTimeStr(LocalDateTimeUtils.format(auth.getCreateTime(), LocalDateTimeUtils.NORMAL_DATETIME_FORMAT_NO_SECOND));
                }
                break;
            }
            case DETAIL: {
                User user = userService.findById(activity.getCreateBy());
                if (null == user) {
                    throw new TipException("用户不存在或已被删除");
                }
                view.setCreator(user.getNickName());
                Media teacherAvatar = mediaService.findById(user.getAvatarId());
                if (null == teacherAvatar || teacherAvatar.getHasDelete()) {
                    throw new TipException("老师的头像信息不存在或已被删除");
                }
                view.setTeacherAvatarUrl(teacherAvatar.getMediaUrl());
                Boolean hasActivityPower = teamService.hasActivityPower(teamId, userId, activity.getId());
                view.setHasActivityPower(hasActivityPower);
                if (hasActivityPower) {
                    view.setHasAuth(false);
                    view.setHasAbility(false);
                } else {
                    Auth auth = authService.findAuthByUserIdAndActivityId(userId, activity.getId());
                    if (null != auth && !auth.getHasDelete()) {
                        //如果已经加入过课程
                        view.setHasAuth(true);
                        view.setHasAbility(userAbilityService.getHasAbility(activity.getId(), userId));
                    } else {
                        view.setHasAuth(false);
                        view.setHasAbility(false);
                    }
                }

                break;
            }
            case HOT:
            case NEW: {
                break;
            }
            case DISCOVER: {
                view.setActivityContentNum(activityContentService.countActivityContentNumByActivityId(activity.getId()));
                User user = userService.findById(activity.getCreateBy());
                if (null == user) {
                    throw new TipException("用户不存在或已被删除");
                }
                view.setCreator(user.getNickName());
                Media teacherAvatar = mediaService.findById(user.getAvatarId());
                if (null == teacherAvatar || teacherAvatar.getHasDelete()) {
                    throw new TipException("老师的头像信息不存在或已被删除");
                }
                view.setTeacherAvatarUrl(teacherAvatar.getMediaUrl());
                break;
            }
            default:
                break;
        }
        return view;
    }

    /**
     * 查找所有活动
     *
     * @return List<com.maixy.studyonlineapi.entity.Activity>
     */
    public List<Activity> findActivityList() {
        return activityMapper.selectList(new QueryWrapper<Activity>()
                .lambda()
                .eq(Activity::getHasDelete, false)
                .orderByDesc(Activity::getCreateTime));
    }

    public Integer countActivity(Long userId) {
        return activityMapper.selectCount(new QueryWrapper<Activity>()
                .lambda()
                .eq(Activity::getCreateBy, userId)
                .eq(Activity::getHasDelete, false));
    }

    public List<Activity> findActivityByCreateBy(Long userId) {
        return activityMapper.selectList(new QueryWrapper<Activity>()
                .lambda()
                .eq(Activity::getCreateBy, userId)
                .eq(Activity::getHasDelete, false)
                .orderByDesc(Activity::getCreateTime));
    }

    public String getExportActivity(Long userId, Long teamId) {
        if (!teamService.hasPower(teamId, userId)) {
            throw new TipException("没有权限");
        }
        Team team = teamService.findById(teamId);
        if (null == team || team.getHasDelete()) {
            throw new TipException("团队不存在或已被删除");
        }
        User user = userService.findById(team.getCreateBy());
        if (null == user) {
            throw new TipException("团队发起人不存在或已被删除");
        }

        List<Activity> activityList = findActivityByCreateBy(team.getCreateBy());
        if (null == activityList || 0 >= activityList.size()) {
            throw new TipException("暂无数据");
        }
        String key = "";
        try {
            HSSFWorkbook workbook = new HSSFWorkbook();
            //创建一个Excel表单,参数为sheet的名字
            HSSFSheet sheet = workbook.createSheet("课程信息");
            //创建表头
            setTitle(workbook, sheet);

            //新增数据行，并且设置单元格数据
            int rowNum = 1;
            for (Activity activity : activityList) {
                HSSFRow row = sheet.createRow(rowNum);
                row.createCell(0).setCellValue(DataTypeUtil.getStr(activity.getId()));
                row.createCell(1).setCellValue(activity.getActivityName());
                ActivityTypeEnum activityTypeEnum = ActivityTypeEnum.getById(activity.getActivityType());
                if (null == activityTypeEnum) {
                    continue;
                }
                row.createCell(2).setCellValue(activityTypeEnum.getDesc());
                row.createCell(3).setCellValue(activity.getActivityDesc());
                row.createCell(4).setCellValue(LocalDateTimeUtils.format(activity.getCreateTime(), LocalDateTimeUtils.NORMAL_DATETIME_FORMAT_NO_SECOND));
                row.createCell(5).setCellValue(activityContentService.countActivityContentNumByActivityId(activity.getId()));
                row.createCell(6).setCellValue(authService.findAuthNumByActivityId(activity.getId()));
                rowNum++;
            }
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            workbook.write(outputStream);
            workbook.close();
            byte[] bytes = outputStream.toByteArray();
            key = "/xlsx/".concat(user.getNickName()).concat("团队的课程信息-").concat(DataTypeUtil.getStr(System.currentTimeMillis())).concat(".xlsx");
            ossUtil.upload(bytes, key);
        } catch (Exception e) {
            log.error("导出失败", e);
            throw new TipException("导出失败");
        }
        return key;
    }

    /***
     * 设置表头
     * @param workbook
     * @param sheet
     */
    private void setTitle(HSSFWorkbook workbook, HSSFSheet sheet){
        HSSFRow row = sheet.createRow(0);
        //设置列宽，setColumnWidth的第二个参数要乘以256，这个参数的单位是1/256个字符宽度
        sheet.setColumnWidth(0, 25*256);
        sheet.setColumnWidth(1, 25*256);
        sheet.setColumnWidth(2, 10*256);
        sheet.setColumnWidth(3, 100*256);
        sheet.setColumnWidth(4, 20*256);
        sheet.setColumnWidth(5, 10*256);
        sheet.setColumnWidth(6, 10*256);

        //设置为居中加粗
        HSSFCellStyle style = workbook.createCellStyle();
        HSSFFont font = workbook.createFont();
        font.setBold(true);
        style.setFont(font);

        HSSFCell cell;
        cell = row.createCell(0);
        cell.setCellValue("课程编号");
        cell.setCellStyle(style);

        cell = row.createCell(1);
        cell.setCellValue("课程名称");
        cell.setCellStyle(style);

        cell = row.createCell(2);
        cell.setCellValue("课程类型");
        cell.setCellStyle(style);

        cell = row.createCell(3);
        cell.setCellValue("课程描述");
        cell.setCellStyle(style);

        cell = row.createCell(4);
        cell.setCellValue("创建时间");
        cell.setCellStyle(style);

        cell = row.createCell(5);
        cell.setCellValue("课件数量");
        cell.setCellStyle(style);

        cell = row.createCell(6);
        cell.setCellValue("报名人数");
        cell.setCellStyle(style);
    }
}
